/**
 * 
 */
package compilador.analizadorSintactico.categoriasSintacticas;

import java.util.ArrayList;

import javax.swing.tree.DefaultMutableTreeNode;

import compilador.analizadorLexico.simbolos.SimboloLexico;
import compilador.analizadorSemantico.tablaSimbolos.TablaSimboloSemantico;
import compilador.interfaces.Sentencia;

/**
 * @author Nolberto Castellanos Rodriguez
 * @author Yurani Alejandra Salamanca Lotero
 *
 * Clase que representa una declaracion de clase
 */
public class DeclaracionClase {
	
//	-------------------------------------------------------------------------------------------------
//	ATRIBUTOS
//	-------------------------------------------------------------------------------------------------
	
	/**
	 *  Atributo que representa la visibilidad de la clase
	 */
	private Visibilidad visibilidad;
	
	/**
	 * Atributo que representa el identificador de una clase
	 */
	private SimboloLexico identificadorClase;
	
	/**
	 *  Atributo que contiene el codigo fuente que hay en la clase
	 */
	private Fuente fuente;
	

//	-------------------------------------------------------------------------------------------------
//	CONSTRUCTOR
//	-------------------------------------------------------------------------------------------------

	/**
	 * Constructor que permite crear una declaracion de clase
	 * @param visibilidad. Visibilidad de la clase
	 * @param identificadorClase. Nombre de la clase
	 * @param fuente. Codigo que hay dentro de la clase
	 */
	public DeclaracionClase (Visibilidad visibilidad, SimboloLexico identificadorClase, Fuente fuente)
	{
		this.visibilidad = visibilidad;
		this.identificadorClase = identificadorClase;
		this.fuente = fuente;
	}

//	-------------------------------------------------------------------------------------------------
//	METODOS
//	-------------------------------------------------------------------------------------------------	
	
	/**
	 * @return
	 */
	public String getJavaCode() {
		String retornable = "";
		if(visibilidad!= null)
			retornable += visibilidad.getJavaCode();
		
		retornable += " class ";
		
		if (identificadorClase != null) 
			retornable += identificadorClase.getLexema();
		
		retornable += "{\n";
		
		if (fuente!= null)
			retornable += fuente.getJavaCode();
			
		return retornable + "}";
	}
	
	/**
	 * Metodo que permite agregar hojas al nodo de la clase
	 * @return el nodo de la clase con sus hojas
	 */
	public DefaultMutableTreeNode getArbolVisual(){
		DefaultMutableTreeNode miRaiz =  new  DefaultMutableTreeNode("Declaracion de Clase");
		
		if(visibilidad != null)
			miRaiz.add(visibilidad.getArbolVisual());
		
		if(identificadorClase != null)
			miRaiz.add(new DefaultMutableTreeNode(identificadorClase.getLexema()));
		
		if (fuente != null) 
			miRaiz.add(fuente.getArbolVisual());
		
		return miRaiz;
	}
	
	public void llenarTabla(TablaSimboloSemantico ts)
	{
		ArrayList<Atributo> atributos = this.fuente.getDeclaracionAtributos().getAtributos();
		ArrayList<Metodo> metodos = this.fuente.getDeclaracionMetodos().getMetodos();
		
		//Almacenar los simbolos de las variables
		for (int i = 0; i < atributos.size(); i++) {
			Atributo at = atributos.get(i);
			ts.agregarSimboloGeneral(at.getIdentificadorAtributo().getLexema(), 
					at.getTipoDato().getTipoDato().getLexema(), identificadorClase.getLexema());
		}
		
		//Almacenar los simbolos de los metodos
		ArrayList<String> parm = new ArrayList<String>();
		for (int i = 0; i < metodos.size(); i++) {
			Metodo mt = metodos.get(i);
			
			if(mt.getListaParametros()!= null || mt.getListaParametros().getListaParametro().size()>0){
				parm = new ArrayList<String>();
				for (ListaParametro parametro : mt.getListaParametros().getListaParametro()) {
					parm.add(parametro.getTipoDato().getTipoDato().getLexema()+"");
					
					ts.agregarSimboloGeneral(parametro.getIdentificadorVarible().getLexema(), 
							parametro.getTipoDato().getTipoDato().getLexema(),
							mt.getIdentificadorMetodo().getLexema());
				}
				
				ts.agregarSimboloMetodo(mt.getIdentificadorMetodo().getLexema(),
						identificadorClase.getLexema(),
							mt.getTipoDato().getTipoDato().getLexema(), parm);
			}
			else
				ts.agregarSimboloMetodo(mt.getIdentificadorMetodo().getLexema(),
						identificadorClase.getLexema(),	mt.getTipoDato().getTipoDato().getLexema(), null);
			
			// Si se crea una variable en una funcion
			for (Sentencia s : mt.getBloqueSentencias().getSentencias()) {
				if(s instanceof Atributo){
					ts.agregarSimboloGeneral(((Atributo) s).getIdentificadorAtributo().getLexema(), 
							((Atributo) s).getTipoDato().getTipoDato().getLexema(), mt.getIdentificadorMetodo().getLexema());
				}
					
			}
		}
	}
	
	/**
	 * @param ts
	 * @param errores
	 * @param claseActual
	 * @param metodoActual
	 */
	public void analizarSemantica(TablaSimboloSemantico ts,	ArrayList<SimboloError> errores, String claseActual, String metodoActual) {
		this.fuente.analizarSemantica(ts, errores, identificadorClase.getLexema(), metodoActual);
	}
	
//	-------------------------------------------------------------------------------------------------
//	Getters & Setters
//	-------------------------------------------------------------------------------------------------	

	
	/**
	 * Metodo que nos retorna el valor de visibilidad
	 * @return  visibilidad. Valor retornado
	 */
	public Visibilidad getVisibilidad() {
		return visibilidad;
	}


	/**
	 * Metodo que permite asignar el valor de visibilidad
	 * @param visibilidad. Valor a asignar visibilidad
	 */
	public void setVisibilidad(Visibilidad visibilidad) {
		this.visibilidad = visibilidad;
	}


	/**
	 * Metodo que nos retorna el valor de identificadorClase
	 * @return  identificadorClase. Valor retornado
	 */
	public SimboloLexico getIdentificadorClase() {
		return identificadorClase;
	}


	/**
	 * Metodo que permite asignar el valor de identificadorClase
	 * @param identificadorClase. Valor a asignar identificadorClase
	 */
	public void setIdentificadorClase(SimboloLexico identificadorClase) {
		this.identificadorClase = identificadorClase;
	}


	/**
	 * Metodo que nos retorna el valor de fuente
	 * @return  fuente. Valor retornado
	 */
	public Fuente getFuente() {
		return fuente;
	}


	/**
	 * Metodo que permite asignar el valor de fuente
	 * @param fuente. Valor a asignar fuente
	 */
	public void setFuente(Fuente fuente) {
		this.fuente = fuente;
	}
	
}
